{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "<a href=\"https://colab.research.google.com/drive/1II7OeTtyQXcNkYDe0WNQPBz1raLx0ejU?usp=sharing\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"></a>"
      ],
      "metadata": {
        "id": "fxA1r24PIdwZ"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Tree of Thoughts (ToT)"
      ],
      "metadata": {
        "id": "UamiOg-KsjUs"
      }
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "-BaYNsMgIZIP"
      },
      "outputs": [],
      "source": [
        "!pip install -qU google-generativeai"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "import google.generativeai as genai\n",
        "import getpass"
      ],
      "metadata": {
        "id": "pGww6hkisl-I"
      },
      "execution_count": 2,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "Get free-tier Google's Gemini API Key here: https://aistudio.google.com/app/apikey"
      ],
      "metadata": {
        "id": "UtLlRLS5spRl"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "API_KEY = getpass.getpass(\"Enter your Google API key: \")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "yi1e5gYxsq8k",
        "outputId": "81226537-4090-41d4-e771-62a8bbceb5fc"
      },
      "execution_count": 3,
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Enter your Google API key: ··········\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "genai.configure(api_key=API_KEY)"
      ],
      "metadata": {
        "id": "0Zt_CCUDsuDW"
      },
      "execution_count": 4,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "class ThoughtNode:\n",
        "    def __init__(self, content, depth=0, parent=None):\n",
        "        self.content = content\n",
        "        self.depth = depth\n",
        "        self.parent = parent\n",
        "        self.children = []\n",
        "        self.value = 0.0  # Evaluation score\n",
        "\n",
        "    def add_child(self, child):\n",
        "        self.children.append(child)\n",
        "        child.parent = self\n",
        "\n",
        "class ToTAgent:\n",
        "    def __init__(self):\n",
        "        self.model = genai.GenerativeModel(\"gemini-2.0-flash-exp\")\n",
        "        self.root = None\n",
        "\n",
        "    def generate_thoughts(self, problem, current_thought, num_thoughts=3):\n",
        "        \"\"\"Generate multiple candidate thoughts\"\"\"\n",
        "        prompt = f\"\"\"Problem: {problem}\n",
        "\n",
        "        Current reasoning: {current_thought}\n",
        "\n",
        "        Generate {num_thoughts} different next reasoning steps or ideas.\n",
        "        List them numbered 1-{num_thoughts}:\"\"\"\n",
        "\n",
        "        response = self.model.generate_content(prompt).text\n",
        "\n",
        "        # Parse thoughts\n",
        "        thoughts = []\n",
        "        for line in response.split(\"\\n\"):\n",
        "            line = line.strip()\n",
        "            if line and (line[0].isdigit() or line.startswith(\"-\")):\n",
        "                # Remove numbering\n",
        "                thought = line.lstrip(\"0123456789.-) \").strip()\n",
        "                if thought:\n",
        "                    thoughts.append(thought)\n",
        "\n",
        "        return thoughts[:num_thoughts]\n",
        "\n",
        "    def evaluate_thought(self, problem, thought):\n",
        "        \"\"\"Evaluate quality of a thought (0-10)\"\"\"\n",
        "        prompt = f\"\"\"Problem: {problem}\n",
        "\n",
        "        Reasoning step: {thought}\n",
        "\n",
        "        Rate this reasoning step's quality (0-10):\n",
        "        - Does it make progress toward solving the problem?\n",
        "        - Is it logical and valid?\n",
        "        - Does it seem promising?\n",
        "\n",
        "        Score (just the number):\"\"\"\n",
        "\n",
        "        response = self.model.generate_content(prompt).text\n",
        "\n",
        "        try:\n",
        "            score = float(response.strip().split()[0])\n",
        "            return min(max(score / 10, 0), 1)  # Normalize to 0-1\n",
        "        except:\n",
        "            return 0.5\n",
        "\n",
        "    def bfs_search(self, problem, max_depth=3, branch_factor=3):\n",
        "        \"\"\"Breadth-First Search through thought tree\"\"\"\n",
        "        print(f\"\\n{'='*60}\")\n",
        "        print(f\"🌳 Tree of Thoughts (BFS)\")\n",
        "        print(f\"{'='*60}\")\n",
        "        print(f\"Problem: {problem}\\n\")\n",
        "\n",
        "        # Initialize root\n",
        "        self.root = ThoughtNode(\"Starting to solve the problem\", depth=0)\n",
        "        queue = [self.root]\n",
        "\n",
        "        best_path = []\n",
        "        best_score = 0\n",
        "\n",
        "        while queue and queue[0].depth < max_depth:\n",
        "            node = queue.pop(0)\n",
        "\n",
        "            print(f\"{'  ' * node.depth}📍 Depth {node.depth}: {node.content[:60]}...\")\n",
        "\n",
        "            # Generate candidate thoughts\n",
        "            thoughts = self.generate_thoughts(problem, node.content, branch_factor)\n",
        "\n",
        "            for thought in thoughts:\n",
        "                # Create child node\n",
        "                child = ThoughtNode(thought, node.depth + 1, node)\n",
        "                node.add_child(child)\n",
        "\n",
        "                # Evaluate thought\n",
        "                score = self.evaluate_thought(problem, thought)\n",
        "                child.value = score\n",
        "\n",
        "                print(f\"{'  ' * child.depth}  ├─ [Score: {score:.2f}] {thought[:50]}...\")\n",
        "\n",
        "                # Track best path\n",
        "                path_score = self._path_score(child)\n",
        "                if path_score > best_score:\n",
        "                    best_score = path_score\n",
        "                    best_path = self._get_path(child)\n",
        "\n",
        "                # Add to queue if promising\n",
        "                if score > 0.4:\n",
        "                    queue.append(child)\n",
        "\n",
        "            print()\n",
        "\n",
        "        return best_path, best_score\n",
        "\n",
        "    def dfs_search(self, problem, max_depth=3, branch_factor=3):\n",
        "        \"\"\"Depth-First Search with backtracking\"\"\"\n",
        "        print(f\"\\n{'='*60}\")\n",
        "        print(f\"🌲 Tree of Thoughts (DFS)\")\n",
        "        print(f\"{'='*60}\")\n",
        "        print(f\"Problem: {problem}\\n\")\n",
        "\n",
        "        self.root = ThoughtNode(\"Starting to solve the problem\", depth=0)\n",
        "\n",
        "        best_path = []\n",
        "        best_score = 0\n",
        "\n",
        "        def dfs(node):\n",
        "            nonlocal best_path, best_score\n",
        "\n",
        "            if node.depth >= max_depth:\n",
        "                # Reached max depth\n",
        "                path_score = self._path_score(node)\n",
        "                if path_score > best_score:\n",
        "                    best_score = path_score\n",
        "                    best_path = self._get_path(node)\n",
        "                return\n",
        "\n",
        "            print(f\"{'  ' * node.depth}📍 Depth {node.depth}: {node.content[:60]}...\")\n",
        "\n",
        "            # Generate and evaluate thoughts\n",
        "            thoughts = self.generate_thoughts(problem, node.content, branch_factor)\n",
        "\n",
        "            evaluated_thoughts = []\n",
        "            for thought in thoughts:\n",
        "                score = self.evaluate_thought(problem, thought)\n",
        "                evaluated_thoughts.append((thought, score))\n",
        "                print(f\"{'  ' * (node.depth + 1)}  ├─ [Score: {score:.2f}] {thought[:50]}...\")\n",
        "\n",
        "            # Sort by score (best first)\n",
        "            evaluated_thoughts.sort(key=lambda x: x[1], reverse=True)\n",
        "\n",
        "            print()\n",
        "\n",
        "            # Explore best thoughts (backtrack from poor ones)\n",
        "            for thought, score in evaluated_thoughts:\n",
        "                if score > 0.3:  # Threshold for exploration\n",
        "                    child = ThoughtNode(thought, node.depth + 1, node)\n",
        "                    child.value = score\n",
        "                    node.add_child(child)\n",
        "\n",
        "                    # Recursively explore\n",
        "                    dfs(child)\n",
        "                else:\n",
        "                    print(f\"{'  ' * (node.depth + 1)}  ⚠️  Backtracking from low-value path\\n\")\n",
        "\n",
        "        dfs(self.root)\n",
        "        return best_path, best_score\n",
        "\n",
        "    def _path_score(self, node):\n",
        "        \"\"\"Calculate cumulative score along path\"\"\"\n",
        "        score = 0\n",
        "        count = 0\n",
        "        while node:\n",
        "            score += node.value\n",
        "            count += 1\n",
        "            node = node.parent\n",
        "        return score / count if count > 0 else 0\n",
        "\n",
        "    def _get_path(self, node):\n",
        "        \"\"\"Get path from root to node\"\"\"\n",
        "        path = []\n",
        "        while node:\n",
        "            path.append(node.content)\n",
        "            node = node.parent\n",
        "        return list(reversed(path))\n",
        "\n",
        "    def solve(self, problem, method=\"bfs\", max_depth=3):\n",
        "        \"\"\"Solve problem using ToT\"\"\"\n",
        "        if method == \"bfs\":\n",
        "            path, score = self.bfs_search(problem, max_depth)\n",
        "        else:\n",
        "            path, score = self.dfs_search(problem, max_depth)\n",
        "\n",
        "        print(f\"{'='*60}\")\n",
        "        print(f\"🏆 BEST REASONING PATH (Score: {score:.2f})\")\n",
        "        print(f\"{'='*60}\")\n",
        "        for i, step in enumerate(path):\n",
        "            print(f\"{i}. {step}\")\n",
        "        print()\n",
        "\n",
        "        # Generate final answer\n",
        "        path_text = \"\\n\".join([f\"{i+1}. {step}\" for i, step in enumerate(path)])\n",
        "\n",
        "        final_prompt = f\"\"\"Problem: {problem}\n",
        "\n",
        "        Reasoning path:\n",
        "        {path_text}\n",
        "\n",
        "        Based on this reasoning, provide the final answer:\"\"\"\n",
        "\n",
        "        final_answer = self.model.generate_content(final_prompt).text\n",
        "\n",
        "        print(f\"{'='*60}\")\n",
        "        print(f\"💡 FINAL ANSWER\")\n",
        "        print(f\"{'='*60}\")\n",
        "        print(final_answer)\n",
        "        print()\n",
        "\n",
        "        return final_answer"
      ],
      "metadata": {
        "id": "uZkM3mVbsvuB"
      },
      "execution_count": 5,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Example 1: Math Puzzle (24 Game)\n",
        "print(\"=\"*60)\n",
        "print(\"EXAMPLE 1: Math Puzzle - Make 24\")\n",
        "print(\"=\"*60)\n",
        "\n",
        "tot1 = ToTAgent()\n",
        "tot1.solve(\n",
        "    \"Use the numbers 4, 6, 8, 8 with operations +, -, *, / to make 24. Each number must be used exactly once.\",\n",
        "    method=\"bfs\",\n",
        "    max_depth=2\n",
        ")\n",
        "\n",
        "\n",
        "# Example 2: Logic Puzzle\n",
        "print(\"\\n\" + \"=\"*60)\n",
        "print(\"EXAMPLE 2: Logic Puzzle\")\n",
        "print(\"=\"*60)\n",
        "\n",
        "tot2 = ToTAgent()\n",
        "tot2.solve(\n",
        "    \"Three people: Alice, Bob, Carol. One always tells truth, one always lies, one alternates. \"\n",
        "    \"Alice says 'Bob is the liar'. Bob says 'Carol alternates'. Who is who?\",\n",
        "    method=\"dfs\",\n",
        "    max_depth=2\n",
        ")\n",
        "\n",
        "\n",
        "# Example 3: Creative Writing\n",
        "print(\"\\n\" + \"=\"*60)\n",
        "print(\"EXAMPLE 3: Creative Story Planning\")\n",
        "print(\"=\"*60)\n",
        "\n",
        "tot3 = ToTAgent()\n",
        "tot3.solve(\n",
        "    \"Write an opening scene for a sci-fi story. The protagonist discovers something mysterious. \"\n",
        "    \"Explore different narrative approaches.\",\n",
        "    method=\"bfs\",\n",
        "    max_depth=2\n",
        ")\n",
        "\n",
        "\n",
        "# Example 4: Strategic Planning\n",
        "print(\"\\n\" + \"=\"*60)\n",
        "print(\"EXAMPLE 4: Strategic Planning\")\n",
        "print(\"=\"*60)\n",
        "\n",
        "tot4 = ToTAgent()\n",
        "tot4.solve(\n",
        "    \"A startup has $100k budget, 3 months, and 2 developers. Should they focus on: \"\n",
        "    \"A) Mobile app, B) Web platform, or C) API service? Consider market, resources, timeline.\",\n",
        "    method=\"dfs\",\n",
        "    max_depth=2\n",
        ")\n",
        "\n",
        "\n",
        "# Example 5: Problem Decomposition\n",
        "print(\"\\n\" + \"=\"*60)\n",
        "print(\"EXAMPLE 5: Complex Problem Decomposition\")\n",
        "print(\"=\"*60)\n",
        "\n",
        "tot5 = ToTAgent()\n",
        "tot5.solve(\n",
        "    \"How can a city reduce traffic congestion by 30% in 2 years? \"\n",
        "    \"Explore different approaches systematically.\",\n",
        "    method=\"bfs\",\n",
        "    max_depth=2\n",
        ")\n",
        "\n",
        "\n",
        "# Example 6: Game Strategy\n",
        "print(\"\\n\" + \"=\"*60)\n",
        "print(\"EXAMPLE 6: Chess Opening Strategy\")\n",
        "print(\"=\"*60)\n",
        "\n",
        "tot6 = ToTAgent()\n",
        "tot6.solve(\n",
        "    \"As white in chess, what's the best opening strategy against the Sicilian Defense? \"\n",
        "    \"Evaluate different approaches.\",\n",
        "    method=\"dfs\",\n",
        "    max_depth=2\n",
        ")\n",
        "\n",
        "\n",
        "print(\"✅ Tree of Thoughts Complete!\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "X7JLmvkvs6G5",
        "outputId": "ce278d3b-f601-4faf-f08c-f9df4e3f0c15"
      },
      "execution_count": 6,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "============================================================\n",
            "EXAMPLE 1: Math Puzzle - Make 24\n",
            "============================================================\n",
            "\n",
            "============================================================\n",
            "🌳 Tree of Thoughts (BFS)\n",
            "============================================================\n",
            "Problem: Use the numbers 4, 6, 8, 8 with operations +, -, *, / to make 24. Each number must be used exactly once.\n",
            "\n",
            "📍 Depth 0: Starting to solve the problem...\n",
            "    ├─ [Score: 1.00] **Focus on getting close to 24:** Try to combine t...\n",
            "    ├─ [Score: 0.70] **Consider division:** Division can drastically ch...\n",
            "    ├─ [Score: 0.80] **Explore multiplication and addition/subtraction:...\n",
            "\n",
            "  📍 Depth 1: **Focus on getting close to 24:** Try to combine two numbers...\n",
            "      ├─ [Score: 0.80] **Focus on using division to simplify:** Can we di...\n",
            "      ├─ [Score: 0.80] **Target a number that's a factor of 24:** Explore...\n",
            "      ├─ [Score: 0.80] **Consider using subtraction to get closer:** Can ...\n",
            "\n",
            "  📍 Depth 1: **Consider division:** Division can drastically change the n...\n",
            "      ├─ [Score: 0.80] **Explore the (8/8) = 1 path further:** Since we'v...\n",
            "      ├─ [Score: 0.90] **Consider using multiplication to get close to 24...\n",
            "      ├─ [Score: 0.70] **Reconsider division with other numbers:** While ...\n",
            "\n",
            "  📍 Depth 1: **Explore multiplication and addition/subtraction:** Try mul...\n",
            "      ├─ [Score: 0.80] **Focus on getting a 3 first:** If we could someho...\n",
            "      ├─ [Score: 0.80] **Target 32 and then subtract 8:** Another approac...\n",
            "      ├─ [Score: 0.70] **Consider fractional results early on:** Since we...\n",
            "\n",
            "============================================================\n",
            "🏆 BEST REASONING PATH (Score: 0.60)\n",
            "============================================================\n",
            "0. Starting to solve the problem\n",
            "1. **Focus on getting close to 24:** Try to combine two numbers to get close to 24, then use the other two to adjust. For example, 6 * 4 = 24, so now can we get zero using 8 and 8?\n",
            "2. **Focus on using division to simplify:** Can we divide any two numbers to get a simple fraction or whole number, and then combine the result with the remaining numbers to reach 24? For instance, 8/4 = 2, and then we need to make 22 from 6 and 8.\n",
            "\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "WARNING:tornado.access:429 POST /v1beta/models/gemini-2.0-flash-exp:generateContent?%24alt=json%3Benum-encoding%3Dint (127.0.0.1) 456.62ms\n"
          ]
        },
        {
          "output_type": "error",
          "ename": "TooManyRequests",
          "evalue": "429 POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?%24alt=json%3Benum-encoding%3Dint: You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits.\n* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 50\nPlease retry in 33.825910095s.",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mTooManyRequests\u001b[0m                           Traceback (most recent call last)",
            "\u001b[0;32m/tmp/ipython-input-3803802080.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0mtot1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mToTAgent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m tot1.solve(\n\u001b[0m\u001b[1;32m      8\u001b[0m     \u001b[0;34m\"Use the numbers 4, 6, 8, 8 with operations +, -, *, / to make 24. Each number must be used exactly once.\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m     \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"bfs\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/tmp/ipython-input-1750466321.py\u001b[0m in \u001b[0;36msolve\u001b[0;34m(self, problem, method, max_depth)\u001b[0m\n\u001b[1;32m    203\u001b[0m         Based on this reasoning, provide the final answer:\"\"\"\n\u001b[1;32m    204\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 205\u001b[0;31m         \u001b[0mfinal_answer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_content\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfinal_prompt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    206\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    207\u001b[0m         \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"{'='*60}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/generativeai/generative_models.py\u001b[0m in \u001b[0;36mgenerate_content\u001b[0;34m(self, contents, generation_config, safety_settings, stream, tools, tool_config, request_options)\u001b[0m\n\u001b[1;32m    329\u001b[0m                 \u001b[0;32mreturn\u001b[0m \u001b[0mgeneration_types\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGenerateContentResponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_iterator\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miterator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    330\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 331\u001b[0;31m                 response = self._client.generate_content(\n\u001b[0m\u001b[1;32m    332\u001b[0m                     \u001b[0mrequest\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    333\u001b[0m                     \u001b[0;34m**\u001b[0m\u001b[0mrequest_options\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/ai/generativelanguage_v1beta/services/generative_service/client.py\u001b[0m in \u001b[0;36mgenerate_content\u001b[0;34m(self, request, model, contents, retry, timeout, metadata)\u001b[0m\n\u001b[1;32m    833\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    834\u001b[0m         \u001b[0;31m# Send the request.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 835\u001b[0;31m         response = rpc(\n\u001b[0m\u001b[1;32m    836\u001b[0m             \u001b[0mrequest\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    837\u001b[0m             \u001b[0mretry\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mretry\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/gapic_v1/method.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, timeout, retry, compression, *args, **kwargs)\u001b[0m\n\u001b[1;32m    129\u001b[0m             \u001b[0mkwargs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"compression\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcompression\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    130\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 131\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mwrapped_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    132\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    133\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/retry/retry_unary.py\u001b[0m in \u001b[0;36mretry_wrapped_func\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    292\u001b[0m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_initial\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_maximum\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmultiplier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_multiplier\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    293\u001b[0m             )\n\u001b[0;32m--> 294\u001b[0;31m             return retry_target(\n\u001b[0m\u001b[1;32m    295\u001b[0m                 \u001b[0mtarget\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    296\u001b[0m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_predicate\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/retry/retry_unary.py\u001b[0m in \u001b[0;36mretry_target\u001b[0;34m(target, predicate, sleep_generator, timeout, on_error, exception_factory, **kwargs)\u001b[0m\n\u001b[1;32m    154\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    155\u001b[0m             \u001b[0;31m# defer to shared logic for handling errors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 156\u001b[0;31m             next_sleep = _retry_error_helper(\n\u001b[0m\u001b[1;32m    157\u001b[0m                 \u001b[0mexc\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    158\u001b[0m                 \u001b[0mdeadline\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/retry/retry_base.py\u001b[0m in \u001b[0;36m_retry_error_helper\u001b[0;34m(exc, deadline, sleep_iterator, error_list, predicate_fn, on_error_fn, exc_factory_fn, original_timeout)\u001b[0m\n\u001b[1;32m    212\u001b[0m             \u001b[0moriginal_timeout\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    213\u001b[0m         )\n\u001b[0;32m--> 214\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mfinal_exc\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0msource_exc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    215\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mon_error_fn\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    216\u001b[0m         \u001b[0mon_error_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/retry/retry_unary.py\u001b[0m in \u001b[0;36mretry_target\u001b[0;34m(target, predicate, sleep_generator, timeout, on_error, exception_factory, **kwargs)\u001b[0m\n\u001b[1;32m    145\u001b[0m     \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    146\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 147\u001b[0;31m             \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtarget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    148\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0minspect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misawaitable\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    149\u001b[0m                 \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_ASYNC_RETRY_WARNING\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/timeout.py\u001b[0m in \u001b[0;36mfunc_with_timeout\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    128\u001b[0m                 \u001b[0mkwargs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"timeout\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mremaining_timeout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    129\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 130\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    131\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    132\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mfunc_with_timeout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/api_core/grpc_helpers.py\u001b[0m in \u001b[0;36merror_remapped_callable\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m     73\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0merror_remapped_callable\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     74\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 75\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mcallable_\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     76\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mgrpc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRpcError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     77\u001b[0m             \u001b[0;32mraise\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_grpc_error\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexc\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/google/ai/generativelanguage_v1beta/services/generative_service/transports/rest.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, request, retry, timeout, metadata)\u001b[0m\n\u001b[1;32m   1159\u001b[0m             \u001b[0;31m# subclass.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1160\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus_code\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m400\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1161\u001b[0;31m                 \u001b[0;32mraise\u001b[0m \u001b[0mcore_exceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrom_http_response\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1162\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1163\u001b[0m             \u001b[0;31m# Return the response\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mTooManyRequests\u001b[0m: 429 POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?%24alt=json%3Benum-encoding%3Dint: You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits.\n* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 50\nPlease retry in 33.825910095s."
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "-IFE4mSPtAN1"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}